package spring.cloud.tasks.executor.task;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.executor.common.Service;
import spring.cloud.tasks.executor.listener.config.TaskConfigurationService;
import spring.cloud.tasks.executor.listener.failover.FailoverService;
import spring.cloud.tasks.executor.trigger.Triggered;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 作业运行时上下文服务.
 */
@Slf4j
@Setter
@Getter
public class TaskExecuteContextService extends Service {
    private TaskConfigurationService taskConfigurationService;
    private FailoverService failoverService;

    public TaskExecuteContextService(TaskExecutor taskExecutor) {
        super(taskExecutor);
    }

    @Override
    public void start() {
        taskConfigurationService = taskExecutor.getTaskConfigurationService();
        failoverService = taskExecutor.getFailoverService();
    }

    /**
     * 获取当前作业服务器运行时分片上下文.
     *
     * @return 当前作业服务器运行时分片上下文
     */
    public TaskExecuteContext getTaskExecuteContext(final Triggered triggered) {
        TaskExecuteContext taskExecuteContext = new TaskExecuteContext();
        taskExecuteContext.setNameSpace(zookeeper.getNameSpace());
        taskExecuteContext.setExecutorId(zookeeper.getExecutorId());
        taskExecuteContext.setTaskId(taskConfigurationService.getTaskId());
        taskExecuteContext.setTaskConfiguration(taskConfiguration);
        taskExecuteContext.setTaskItemTotalCount(taskConfigurationService.getTaskItemTotalCount());
        List<Integer> taskItemList = getTaskItemIndexList();
        removeRunningTaskItemIndexList(taskItemList);
        taskExecuteContext.setTaskItemIndexList(taskItemList);
        taskExecuteContext.setTaskParameter(taskConfigurationService.getTaskParameter());
        taskExecuteContext.setCustomContext(taskConfigurationService.getCustomContext());
        //
        taskExecuteContext.setTriggered(triggered);
        if (taskExecuteContext.getTaskItemIndexList().isEmpty()) {
            return taskExecuteContext;
        }
        Map<Integer, String> taskItemIndexToTaskItemAndParameterMap = taskConfigurationService.getTaskItemIndexToTaskItemAndParameterMap();
        for (int taskItemIndex : taskExecuteContext.getTaskItemIndexList()) {
            if (taskItemIndexToTaskItemAndParameterMap.containsKey(taskItemIndex)) {
                taskExecuteContext.getTaskItemIndexToTaskItemAndParameterMap().put(taskItemIndex, taskItemIndexToTaskItemAndParameterMap.get(taskItemIndex));
            }
        }
        if (taskConfiguration.getTimeoutSeconds() > 0) {
            taskExecuteContext.setTimeoutSeconds(taskConfiguration.getTimeoutSeconds());
        }
        return taskExecuteContext;
    }

    private void removeRunningTaskItemIndexList(final List<Integer> taskItemIndexList) {
        List<Integer> list = new ArrayList<>(taskItemIndexList.size());
        for (int taskItemIndex : taskItemIndexList) {
            if (isRunningTaskItem(taskItemIndex)) {
                list.add(taskItemIndex);
            }
        }
        taskItemIndexList.removeAll(list);
    }

    private boolean isRunningTaskItem(final int taskItemIndex) {//
        return taskExecutor.getTaskNodeStorage().isTaskNodeExisted(ExecuteNode.getRunningNode(taskItemIndex));
    }

    /**
     * 获取分片项列表。
     *
     * @return 分片项列表。
     */
    public List<Integer> getTaskItemIndexList() {
        List<Integer> shardingTaskItemIndexList = taskExecutor.getShardingService().getShardingTaskItemIndexList();
        boolean isEnabledReport = taskConfigurationService.isEnabled();
        if (taskConfigurationService.isFailover() && isEnabledReport) {
            List<Integer> failoverTaskItemIndexList = failoverService.getFailoverTaskItemIndexList();
            if (!failoverTaskItemIndexList.isEmpty()) {
                return failoverTaskItemIndexList;
            } else {
                shardingTaskItemIndexList.removeAll(failoverService.getTakeOffTaskItemIndexList());
                return shardingTaskItemIndexList;
            }
        } else {
            return shardingTaskItemIndexList;
        }
    }
}
